/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.mobiwebinc.compconn.communication;

import com.mobiwebinc.compconn.events.command.Command;
import com.mobiwebinc.compconn.configuration.Constant;
import java.awt.image.RenderedImage;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;

/**
 *
 * @author suraj
 */
public class IOHandler {

    private Socket socket;
    private DataInputStream in;
    private DataOutputStream out;
    private PrintStream prn;
    private boolean connected;
    private ImageWriter writer;
    private ImageWriteParam iwp;
    private long lastCommunicated;
    private ByteArrayOutputStream os ;

    public IOHandler(Socket socket) {
        this.socket = socket;
        try {
            in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
            out = new DataOutputStream(socket.getOutputStream());
            prn = new PrintStream(socket.getOutputStream());
        } catch (IOException ex) {
            connected = false;
            Logger.getLogger(IOHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
        setupImageWriter(1);
        connected = true;
    }

    public void close() {
        sendMsg(Command.TERMINATE);
        try {
            Thread.sleep(Constant.TERMINATE_TIME);
        } catch (InterruptedException ex) {
            Logger.getLogger(IOHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void disconnect() {
        connected = false;
        try {
            getSocket().close();
        } catch (IOException ex) {
            Logger.getLogger(IOHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
 
    public void sendReply(String msg) {
        getPrn().print(msg);
        getPrn().flush();
    }

    public void sendMsg(String msg) {
        try {
            out.writeInt(msg.length());
            out.write(Constant.STRING_TYPE);
            getPrn().print(msg);
            out.flush();
        } catch (IOException ex) {
            Logger.getLogger(IOHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }


    public void sendImage(RenderedImage image) {
        try {
            writer.write(null, new IIOImage(image, null, null), iwp);
//            System.out.println("sent " + os.size());
            out.writeInt(os.size());
            out.write(Constant.IMAGE_TYPE);
            out.write(os.toByteArray());
            out.flush();
            os.reset();
        } catch (IOException ex) {
            disconnect();
            Logger.getLogger(IOHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void sendInt(int value) {
        try {
            out.writeInt(4);
            out.write(Constant.INT_TYPE);
            out.writeInt(value);
            out.flush();
        } catch (IOException ex) {
            Logger.getLogger(IOHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public String readMsg() {
        String msg = "";
        try {
            int len = in.readInt();
            byte cbuf[] = new byte[len];
            in.readInt();
            in.read(cbuf);
            msg = new String(cbuf);
            setLastCommunicated(System.currentTimeMillis()+100000);
            if (len == 0 || msg == null) {
                msg = "";
                disconnect();
            }
        } catch (Exception ex) {
            disconnect();
            Logger.getLogger(IOHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
        return msg.trim();
    }

    public void setupImageWriter(float quality) {
        Iterator iter = ImageIO.getImageWritersByFormatName("jpg");
        writer = (ImageWriter) iter.next();
        iwp = writer.getDefaultWriteParam();
        iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        iwp.setCompressionQuality(quality);
        os = new ByteArrayOutputStream();
        try {
            writer.setOutput(ImageIO.createImageOutputStream(os));
        } catch (IOException ex) {
            Logger.getLogger(IOHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * @return the socket
     */
    public synchronized Socket getSocket() {
        return socket;
    }

    /**
     * @param socket the socket to set
     */
    public synchronized void setSocket(Socket socket) {
        this.socket = socket;
    }

    /**
     * @return the out
     */
    public DataOutputStream getOut() {
        return out;
    }

    /**
     * @param out the out to set
     */
    public void setOut(DataOutputStream out) {
        this.out = out;
    }

    /**
     * @return the prn
     */
    public PrintStream getPrn() {
        return prn;
    }

    /**
     * @param prn the prn to set
     */
    public void setPrn(PrintStream prn) {
        this.prn = prn;
    }

    /**
     * @return the connected
     */
    public boolean isConnected() {
        return connected;
    }

    /**
     * @param connected the connected to set
     */
    public void setConnected(boolean connected) {
        this.connected = connected;
    }

    public String getRemoteHostName() {
        return socket.getInetAddress().getHostName();
    }

    /**
     * @return the lastCommunicated
     */
    public synchronized long getLastCommunicated() {
        return lastCommunicated;
    }

    /**
     * @param lastCommunicated the lastCommunicated to set
     */
    public synchronized void setLastCommunicated(long lastCommunicated) {
        this.lastCommunicated = lastCommunicated;
    }
}
